﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.ServiceModel.Activation;
using PublicLib.Lib.Help;
using Newtonsoft.Json;
using DataModel.Receive.Frame;
using DataModel.Send.Frame;
using PublicLib.Lib.Security;
using PublicLib.Def;
using DataModel.Send;

namespace WebServerHntj
{
    // 注意: 使用“重构”菜单上的“重命名”命令，可以同时更改代码、svc 和配置文件中的类名“ServiceBeatheart”。
    // 注意: 为了启动 WCF 测试客户端以测试此服务，请在解决方案资源管理器中选择 ServiceBeatheart.svc 或 ServiceBeatheart.svc.cs，然后开始调试。
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ServiceBeatheart : IServiceBeatheart
    {
        /// <summary>
        /// 心跳
        /// </summary>
        /// <param name="user"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public Stream Pulse(string user, string data)
        {
            Debug.WriteLine(DateTime.Now.ToString() + " ServiceBeatheart:Pulse." + "Data:" + data);
            if (!user.Equals("Hntj", StringComparison.CurrentCultureIgnoreCase))
                return null;
            HeaderBase frame = CheckDBOpera(user);
            frame.Stage = "";
            string res = string.Empty;
            using (MemoryStream ms = new MemoryStream())
            {
                res = GetReturn(user, frame, ms);
            }
            return res.ToStream();
        }
        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="user"></param>
        /// <param name="operation"></param>
        /// <param name="inputData"></param>
        /// <returns></returns>
        public Stream PostData(string user, string operation, Stream inputData)
        {
            Debug.WriteLine(DateTime.Now.ToString() + " ServiceBeatheart:PostData");
            Debug.WriteLine("user:" + user + ",operation:" + operation);
            if (!user.Equals("Hntj", StringComparison.CurrentCultureIgnoreCase))
            {
                Debug.WriteLine("用户名错误");
                return null;
            }
            HeaderBase frame = CheckDBOpera(user);
            string res = String.Empty;

            using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    string comHere = new StreamReader(inputData, PublicDef.PageEncoding).ReadToEnd();

                    res = tryToDecrypt(user, frame, comHere);
                    Debug.WriteLine(res);
                    Type type = null;
                    if (res != null && !string.IsNullOrWhiteSpace(res))
                    {
                        type = tryCheckOpera(operation, frame);
                    }
                    if (type != null)
                    {
                        getReceiveFrame(frame, res, type, user, operation);
                    }
                    else
                    {
                        frame.Code = DataModel.PublicModel.Typedef.ErrorType.ErrorOpera;
                        frame.Message = "没有获得正确的操作类型";
                    }
                    res = GetReturn(user, frame, ms);
                    Debug.WriteLine(AesSecurity.Decrypt(res, user + (int)(DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 1)).TotalDays));
                }
                catch (Exception ex) { Debug.WriteLine(ex.ToString()); }
            }
            return res.ToStream();
        }
        /// <summary>
        /// 获得返回数据
        /// </summary>
        /// <param name="user"></param>
        /// <param name="frame"></param>
        /// <param name="ms"></param>
        /// <returns></returns>
        private static string GetReturn(string user, HeaderBase frame, MemoryStream ms)
        {
            string res;
            TextWriter tr = new StreamWriter(ms);
            JsonSerializer.CreateDefault().Serialize(tr, frame);
            tr.Flush();
            ms.Position = 0;
            res = AesSecurity.Encrypt(ms.GetBuffer(), user + (int)(DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 1)).TotalDays);
            return res;
        }
        /// <summary>
        /// 检查数据库，组建返回帧
        /// </summary>
        /// <param name="frame"></param>
        /// <param name="user"></param>
        private HeaderBase CheckDBOpera(string user)
        {
            using (energybasedbEntities entity = new energybasedbEntities())
            {
                HeaderBase frame = null;
                operationtable single = null;
                try
                {
                    single = (from c in entity.operationtable where c.userid == user select c).FirstOrDefault();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.ToString());
                }
                if (single != null && single.operation != DataModel.PublicModel.Typedef.ErrorType.OK.ToString())
                {
                    DataModel.PublicModel.Typedef.Operator opera;
                    if (!Enum.TryParse(single.operation, out opera))
                    {
                        frame = new RequestNon();
                    }
                    switch (opera)
                    {
                        case DataModel.PublicModel.Typedef.Operator.hisdata:
                            frame = getSendFrame(single.data, typeof(RequestHisdata));
                            break;
                        case DataModel.PublicModel.Typedef.Operator.documentStruct:
                            frame = getSendFrame(single.data, typeof(RequestDocument));
                            break;
                        case DataModel.PublicModel.Typedef.Operator.treeStruct:
                            frame = getSendFrame(single.data, typeof(RequestTree));
                            break;
                        default:
                            frame = new RequestNon();
                            break;
                    }
                    single.data = string.Empty;
                    single.operation = DataModel.PublicModel.Typedef.Operator.non.ToString();
                    entity.SaveChanges();
                }
                else
                {
                    frame = new RequestNon();
                }
                if (frame is RequestNon)
                {
                    frame.Code = DataModel.PublicModel.Typedef.ErrorType.OK;
                    frame.Message = string.Empty;
                    frame.Stage = single.stage;
                    frame.User = user;
                }
                return frame;
            }
        }
        /// <summary>
        /// 反序列化获得发送数据帧
        /// </summary>
        /// <param name="frame"></param>
        /// <param name="res"></param>
        /// <param name="type"></param>
        private static HeaderBase getSendFrame(string res, Type type)
        {
            object obj = null;
            HeaderBase frame = null;
            TextReader tw = new StreamReader(new MemoryStream(PublicDef.PageEncoding.GetBytes(res)));
            try
            {
                obj = JsonSerializer.CreateDefault().Deserialize(tw, type);
                if (obj is HeaderBase)
                    frame = obj as HeaderBase;
            }
            catch
            {
                frame = new RequestNon();
                frame.Code = DataModel.PublicModel.Typedef.ErrorType.ErrorOpera;
                frame.Message = "JSON文件格式错误";
            }
            if (frame == null)
            {
                frame = new RequestNon();
                frame.Code = DataModel.PublicModel.Typedef.ErrorType.Undefine;
                frame.Message = "JSON文件格式错误";
            }
            return frame;
        }
        /// <summary>
        /// 反序列化获得接收数据帧
        /// </summary>
        /// <param name="frame"></param>
        /// <param name="res"></param>
        /// <param name="type"></param>
        private static void getReceiveFrame(HeaderBase frame, string res, Type type, string user, string operation)
        {
            object obj = null;
            TextReader tw = new StreamReader(new MemoryStream(PublicDef.PageEncoding.GetBytes(res)));
            try
            {
                obj = JsonSerializer.CreateDefault().Deserialize(tw, type);
            }
            catch
            {
                frame.Code = DataModel.PublicModel.Typedef.ErrorType.ErrorOpera;
                frame.Message = "JSON文件格式错误";
            }
            if (obj == null)
            {
                frame.Code = DataModel.PublicModel.Typedef.ErrorType.Undefine;
                frame.Message = "JSON文件格式错误";
            }
            if (frame.Code == DataModel.PublicModel.Typedef.ErrorType.OK)
            {
                frame.Message = "接收数据完成";
                using (var entity = new energybasedbEntities())
                {
                    try
                    {
                        if (obj as DataModel.Receive.HeaderBase != null)
                            frame.Stage = (obj as DataModel.Receive.HeaderBase).Stage;
                        else
                            Debug.WriteLine("obj is not DataModel.Receive.HeaderBase");
                        entity.hisdata.Add(new hisdata() { userID = user, saveTime = DateTime.Now, data = res, stage = frame.Stage, operation = operation });
                        entity.SaveChanges();
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.ToString());
                    }
                }
            }
        }
        /// <summary>
        /// 判断操作类型获取回应帧类型
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="frame"></param>
        /// <returns></returns>
        private static Type tryCheckOpera(string operation, HeaderBase frame)
        {
            Type type = null;
            DataModel.PublicModel.Typedef.Operator opera;
            if (!Enum.TryParse(operation, out opera))
            {
                return null;
            }
            switch (opera)
            {
                case DataModel.PublicModel.Typedef.Operator.hisdata:
                    type = typeof(DataModel.Receive.Frame.ResponseHis);
                    break;
                case DataModel.PublicModel.Typedef.Operator.realdata:
                    type = typeof(DataModel.Receive.Frame.ResponseReal);
                    break;
                case DataModel.PublicModel.Typedef.Operator.treeStruct:
                    frame.Code = DataModel.PublicModel.Typedef.ErrorType.ErrorOpera;
                    frame.Message = "该操作尚未实现";
                    break;
                case DataModel.PublicModel.Typedef.Operator.documentStruct:
                    frame.Code = DataModel.PublicModel.Typedef.ErrorType.ErrorOpera;
                    frame.Message = "该操作尚未实现";
                    break;
                default:
                    frame.Code = DataModel.PublicModel.Typedef.ErrorType.ErrorOpera;
                    frame.Message = "该操作未定义";
                    break;
            }
            return type;
        }
        /// <summary>
        /// 解密数据
        /// </summary>
        /// <param name="user"></param>
        /// <param name="frame"></param>
        /// <param name="comHere"></param>
        /// <returns></returns>
        private static string tryToDecrypt(string user, HeaderBase frame, string comHere)
        {
            string res = AesSecurity.Decrypt(comHere, user + (int)(DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 1)).TotalDays);
            if (res == null || string.IsNullOrWhiteSpace(res))
            {
                res = AesSecurity.Decrypt(comHere, user + (int)((DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 1)).TotalDays + 1));
            }
            if (res == null || string.IsNullOrWhiteSpace(res))
            {
                res = AesSecurity.Decrypt(comHere, user + (int)((DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 1)).TotalDays - 1));
            }
            if (res == null || string.IsNullOrWhiteSpace(res))
            {
                frame.Code = DataModel.PublicModel.Typedef.ErrorType.ErrorKey;
                frame.Message = "KEY错误，无法解密";
            }
            return res;
        }
    }
}
